﻿#region Imports
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using DataAnnotationsContrib;
using DataAnnotationsContrib.Interfaces;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endregion

namespace DataAnnotationsContrib.Tests.Framework
{
    /// <summary>
    /// Serves as a base class for all checkdigit tests. Performs basic minimal test functionality
    /// by exercising an ICheckDigitAlgorithm with the passed valid and invalid values.
    /// </summary>
    [TestClass]
    public abstract class CheckDigitAlgorithmTest<TAlgorithm>
        where TAlgorithm : ICheckDigitAlgorithm
    {
        #region Infrastructure
        public TestContext TestContext { get; set; }

        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // [TestCleanup()]
        // public void MyTestCleanup() { }

        private IList<string> ValidValues { get; set; }
        private IList<string> InvalidValues { get; set; }
        private IList<string> ApplyCheckSumValues { get; set; }

        protected CheckDigitAlgorithmTest(
            IList<string> validValues, IList<string> invalidValues, IList<string> applyCheckSumValues)
        {
            Assert.IsNotNull(validValues, "validValues must be supplied.");
            Assert.AreNotEqual(0, validValues.Count, "validValues must not contain more 0 items.");
            Assert.IsNotNull(validValues, "invalidValues must be supplied.");
            Assert.AreNotEqual(0, invalidValues.Count, "validValues must not contain more 0 items.");
            Assert.IsNotNull(applyCheckSumValues, "invalidValues must be supplied.");
            Assert.AreNotEqual(0, applyCheckSumValues.Count, "validValues must not contain more 0 items.");

            this.ValidValues = validValues;
            this.InvalidValues = invalidValues;
            this.ApplyCheckSumValues = applyCheckSumValues;
        }

        protected virtual ICheckDigitAlgorithm CreateAlgorithm()
        {
            return Activator.CreateInstance<TAlgorithm>();
        }
        #endregion

        #region Tests
        public void TestAllValidValuesShouldVerifyTrue()
        {
            TestHelper.Trace(this.TestContext, this.ValidValues);

            var algorithm = CreateAlgorithm();
            foreach (var value in this.ValidValues)
            {
                Assert.IsTrue(algorithm.Verify(value), String.Format("Value '{0}' unexpectedly failed verification.", value));
            }
        }
        public void TestAllInvalidValuesShouldVerifyFalse()
        {
            TestHelper.Trace(this.TestContext, this.InvalidValues);

            var algorithm = CreateAlgorithm();
            foreach (var value in this.InvalidValues)
            {
                Assert.IsFalse(algorithm.Verify(value), String.Format("Value '{0}' unexpectedly passed verification.", value));
            }
        }
        public void TestApplyAndRemoveChecksumAgrees()
        {
            TestHelper.Trace(this.TestContext, this.ApplyCheckSumValues);

            var algorithm = CreateAlgorithm();
            foreach (var value in this.ApplyCheckSumValues)
            {
                Assert.IsFalse(String.IsNullOrEmpty(algorithm.ExtractCheckDigit(algorithm.AddCheckDigit(value))));
                Assert.AreNotEqual(value, algorithm.AddCheckDigit(value));
                Assert.AreEqual(value, algorithm.RemoveCheckDigit(algorithm.AddCheckDigit(value)), "Apply and remove check digit did not equal original value.");
            }
        }
        #endregion
    }
}
